#include <stdio.h> 
#include <errno.h> 
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> 
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <netdb.h>
#include <time.h>
#include <signal.h>
#include <getopt.h>
#include <dirent.h>
#include "header.h"


void sig_stop(int signum);

int g_stop = 0;
int connect_server(int port,char *ser_ip);

void print_usage(char *progname)             //打印帮助信息
{
      printf("-d(--daemon):let program run in the background.\n");
      printf("-i(--ipaddr):sepcify server ip address\n");
      printf("-p(--port):sepcify server port.\n");
      printf("-h(--help):printf this help information.\n");
      printf("-t(time):enter the sampling interval time.\n");
      return ;
}


void time_get(char *date_time)
{
	time_t            timep;
	struct tm         *p;		//p为一个指向tm结构体类型的指针

	time(&timep);	
	p = gmtime(&timep);        //gmtime()时间转换

	 snprintf(date_time, 32, "%d-%d-%d %d:%d:%d", 1900+p->tm_year, 1+p->tm_mon, p->tm_mday, (p->tm_hour + 8), p->tm_min, p->tm_sec);

	 return ;
}

int temperper_get(float *temper)
{
	int              fd = -1;
	int              found = 0;
	char             f_name[32];
	char             cache[512];
	char             *ptr = NULL;
	char             path[128]="/sys/bus/w1/devices/";
	DIR              *dirp = NULL;
	struct dirent    *direntp = NULL;


	dirp = opendir(path);   	//打开温度传感器设备文件夹
	if(dirp == NULL) 
	{
		 printf("open folder failure: %s\n", strerror(errno)); 

		 return 0 ;

	}

	while ((direntp = readdir(dirp)) != NULL) //查找温度传感器对应文件夹
	{
		if (strstr(direntp->d_name, "28-")) 
		{
			strncpy(f_name, direntp->d_name, sizeof(f_name)); 
                        found = 1;    //设置found为1，即代表找到相应文件夹 
		}
		 
        }
	closedir(dirp); 		//关闭opendir()函数打开的文件夹

	if (!found)     // 即表明未检索到目的文件夹
	{
		 printf("Can not find the folder\n"); 
		 return 0 ;

	}
	strncat(path, f_name, sizeof(path)-strlen(path)); 
	strncat(path, "/w1_slave", sizeof(path)-strlen(path)); //将设备文件夹下存放温度的文件连接在path路径后

	if((fd = open(path, O_RDONLY)) < 0) //打开存放温度数据的文件
	{
		 printf("open file failure: %s\n", strerror(errno)); 
		 return 0;
	}
	memset(cache, 0, sizeof(cache)); 
	if (read(fd, cache, sizeof(cache)) < 0) 
	{
		 printf("Read data failure: %s\n", strerror(errno)); 
		 return 0;
	}
	
	ptr = strstr(cache, "t=");     //利用strstr(0函数进行字符串查找，目的是找到相应温度数值
        if (!ptr) 
	{
		printf("Can not find \"t=\"!\n");
		return 0;
	}
	
	ptr += 2;   //ptr指针后移两个字符单位(“t= ”)，其后即为温度数据
	*temper = atof(ptr)/1000; 	//将以字符串形式存储的温度数据转换成浮点数

	close(fd);         //关闭open()打开文件时创建的文件描述符
	return 0;
}



int main(int argc,char **argv)
{
    int                     daemon_run;
    int                     opt;
    int                      con_fd = -1; 
    int                     idx;
    int                     S_time;
    int                     log_fd;
    int                     sock_fd=-1;
    int                     conn_fd=-1;
    int                     rv=-1;
    char                    *servip=NULL;
    int                     port=0;
    int                     ch;
    char                    buf[1024];
    char                    date_time[32];
    char                    *id = "yjn";  //定义设备ID，
    char                    *hostname;
    float                   temper;
    struct hostent           *getname = NULL;
    struct sockaddr_in      serv_addr;
    /*
                daemon：程序后台运行；
                time：待设定的上报时间间隔；
		name：设置待连服务器域名或者IP；
		port：设置待连服务器端口；
		help：命令行参数输入错误时，打印帮助信息。
    */
    struct option           opts[]={
	                    {"daemon",no_argument,NULL,'d'},
			    {"time",required_argument,NULL,'t'},
	                    {"ipaddr",required_argument,NULL,'i'},
	                    {"port",required_argument,NULL,'p'},
	                    {"help",no_argument,NULL,'h'},
			    {NULL,0,NULL,0}                             
                            };

    printf("start\n");
    while ( (ch=getopt_long(argc,argv,"dt:i:p:h",opts,NULL)) != -1)
    {
          printf("ch:%c\n",ch);
	  switch (ch)
	  {
		  case'd':
			  daemon_run = 1;
			  break;
                  case't':
                          S_time = atoi(optarg);
                          break;			  
		         
		  case 'i':
			  servip=optarg;
			  break;

                  case 'p':
                          port=atoi(optarg);
                          break;

                  case 'h':
                          print_usage(argv[0]);
                          return 0;			  
	  }  
    }
    
    if(! servip || !port)
    {
	    print_usage(argv[0]);
	    return 0;
     
    }

    getname = gethostbyname(hostname); 
    if (getname == NULL)
    {
	    printf("Get hostname failure : %s\n", strerror(h_errno));
	    return 0;
    }


    servip = inet_ntoa(*(struct in_addr *)getname->h_addr);
    if (servip == NULL)
    {
           printf("Get ser_ip failure : %s\n", strerror(errno));
	   return 0;	    
    }
    printf("ser_ip[%s]\n", servip);
    
    if (daemon_run)   //守护进程函数
    {
	    printf("Program %s is running at the background now\n", argv[0]);

	    log_fd = open("receive_temper.log",  O_CREAT|O_RDWR, 0666);  //创建日志系统，程序后台运行后，将所有打印信息打印在日志文件中

	    if (log_fd < 0)
	    {
		     printf("Open the logfile failure : %s\n", strerror(errno));
		     return 0;
	    }

	     dup2(log_fd, STDOUT_FILENO);
	     dup2(log_fd, STDERR_FILENO);    //标准输出及标准出错重定向，重定向至日志文件

	     if ((daemon(1, 1)) < 0)  //设置deamon()函数两个参数为1
	     {
		     printf("Deamon failure : %s\n", strerror(errno));
		     return 0;
	     }
    }	    

     signal(SIGUSR1, sig_stop);	//捕捉到kill信号后，调用sig_stop(),将g_stop设置为1，程序结束
     signal(SIGPIPE, SIG_IGN);	//屏蔽SIGPIPE信号，因为当服务器主动断开socket连接后，客户端会接收到SIGPIPE信号，自动退出。为达到服务器主动断开socket连接后，客户端重连服务器端的目的，这里必须屏蔽掉SIGPIPE信号
    
    conn_fd = socket(AF_INET, SOCK_STREAM, 0); 
    if(conn_fd < 0) 
    {
          printf("create socket failure: %s\n", strerror(errno)); 
          return -1;
    }

    

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    inet_aton( servip, &serv_addr.sin_addr );
   
    if( connect(conn_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))  < 0)     //ipv4对应sockaddr_in类型，此时应进行强制类型转换为通用套接字sockaddr类型
    {
           printf("connect to server [%s:%d] failure: %s\n", servip, port, strerror(errno)); 
           return 0; 
    } 
     
    printf("Establish the connection with server successfully\n");
    return con_fd;



    memset(buf, 0, sizeof(buf)); 
    while( !g_stop)
    {
	    if ((temperper_get(&temper)) < 0)	
	    {
		     printf("Get temperature failure!\n");
		     continue;
	    }
	    time_get(date_time);		//调用time_get()函数，获取时间

	     snprintf(buf, sizeof(buf),"%s/%s/%.1f%c", id, date_time, temper, 'C');

             if (sock_fd < 0)               //未能连接到服务器
	     {
		     if ((sock_fd = connect_server(port, servip)) < 0)
		     {
			     printf("Now establish the connection with server again!\n");
			      printf("\n");
			      continue;
		     }
	     }

	     if (sock_fd >= 0) 
	     {
		     rv = write(sock_fd, buf, sizeof(buf));
		     if (rv >= 0)
		     {
			     printf("Send messege to server successfully!\n");
		     }
		     else
		     {
			     printf("Send messege to server failure : %s\n", strerror(errno));
			     close(sock_fd); 
			     sock_fd = -1;		//上传数据失败，将sock_fd重设为-1，下次循环重新连接服务器
		     }
	     }


	     sleep(S_time);       //休眠，达到一定时间间隔后，将数据上报服务器的目的
    }

    close(conn_fd); 
    return 0 ;
}

void sig_stop(int signum)
{
	 if (SIGUSR1 == signum)
	 {
		  g_stop = 1;        
	 }
	 return ;

}

